﻿using Ndex.Core;
using Ndex.Core.Class;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Mvc;

namespace System
{
    public static class StringExt
    {

        public static string Trim(this string val)
        {
            if (IsEmpty(val))
                return string.Empty;
            return val.Trim();
        }

        public static string TrimLower(this string val)
        {
            if (IsEmpty(val))
                return string.Empty;
            return val.Trim().ToLower();
        }

        public static string Get(params string[] vals)
        {
            foreach (var val in vals)
                if (!IsEmpty(val))
                    return val.Trim();
            return string.Empty;
        }

        public static MvcHtmlString ToHtml(this string val)
        {
            return new MvcHtmlString(val);
        }

        public static bool IsEmpty(this string val)
        {
            return string.IsNullOrWhiteSpace(val);
        }

        public static long ToLong(this string val)
        {
            long result = 0;
            long.TryParse(val, out result);
            return result;
        }

        public static bool EqualEx(this string val, string par)
        {
            var a = Trim(val);
            var b = Trim(par);
            return a.Equals(b, StringComparison.OrdinalIgnoreCase);
        }

        public static Dictionary<string, string> GetChanges(this Dictionary<string, string> vals, Dictionary<string, string> objs)
        {
            var format = "changed from {0} to {1}";
            var result = new Dictionary<string, string>();
            foreach (var key in vals.Keys)
            {
                var val = Trim(vals[key]);
                var obj = Trim(objs[key]);
                if (!val.EqualEx(obj))
                    result[key] = string.Format(format, val, obj);
            }
            return result;
        }

        public static string Combine(params string[] vals)
        {
            return Combine(vals, " ");
        }

        public static string Combine(this IEnumerable<string> vals, string separator)
        {
            vals = vals.Trim();
            return string.Join(separator, vals);
        }

        public static string ToTripleDES(this string val, string salt = "123456789ttnk")
        {
            MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
            TripleDESCryptoServiceProvider algorithm = new TripleDESCryptoServiceProvider();
            algorithm.Key = hashmd5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(salt));
            algorithm.Mode = CipherMode.ECB; //CBC, CFB
            var buff = ASCIIEncoding.ASCII.GetBytes(val);
            return Convert.ToBase64String(algorithm.CreateEncryptor().TransformFinalBlock(buff, 0, buff.Length));
        }

        public static string FromTripleDES(this string encrypted, string password = "123456789ttnk")
        {
            try
            {
                var hashmd5 = new MD5CryptoServiceProvider();
                var pwdhash = hashmd5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(password));
                var des = new TripleDESCryptoServiceProvider();
                des.Key = pwdhash;
                des.Mode = CipherMode.ECB; //CBC, CFB
                var buff = Convert.FromBase64String(encrypted);
                return ASCIIEncoding.ASCII.GetString(des.CreateDecryptor().TransformFinalBlock(buff, 0, buff.Length));
            }
            catch
            {
                return "";
            }
        }

        public static string ToSHA1(this string val)
        {
            val = val.Trim();
            var algorithm = SHA1.Create();
            byte[] code = algorithm.ComputeHash(Encoding.UTF8.GetBytes(val));
            return Convert.ToBase64String(code);
        }

        public static string[] Split(this string val, string separator, StringSplitOptions option = StringSplitOptions.RemoveEmptyEntries)
        {
            if (val == null)
                return new string[0];
            return val.Split(new string[] { separator }, StringSplitOptions.RemoveEmptyEntries);
        }



        public static bool IsEmail(this string s)
        {
            if (string.IsNullOrWhiteSpace(s))
                return true;
            var regexString = @"^[\w!#$%&'*+\-/=?\^_`{|}~]+(\.[\w!#$%&'*+\-/=?\^_`{|}~]+)*" + "@" + @"((([\-\w]+\.)+[a-zA-Z]{2,4})|(([0-9]{1,3}\.){3}[0-9]{1,3}))$";
            var regex = new System.Text.RegularExpressions.Regex(regexString);
            return regex.IsMatch(s);
        }

        public static string IsEmailList(this string s)
        {
            var emails = s.Split(";");
            foreach (var email in emails)
            {
                var addresses = email.Split(" ").Trim();
                var address = addresses.LastOrDefault();
                if (addresses.Count() < 2)
                    return "Email addresses is invalid. It should contains Person Name and email address";

                if (!address.IsEmail())
                    return "One of email addresses is invalid";
            }
            return "";
        }

        public static EmailAddress ParseEmail(this string email)
        {
            var result = new EmailAddress();
            if (string.IsNullOrWhiteSpace(email))
                return result;

            var s = email.Split(new string[] { "<", ">", " " }, StringSplitOptions.RemoveEmptyEntries).ToList();
            result.Email = s.LastOrDefault();
            if (s.Count > 1)
            {
                s.Remove(result.Email);
                result.Name = StringExt.Combine(s, " ");
            }
            return result;
        }

        public static string TrimEmailList(this string s)
        {
            var emails = s.Split(";").Distinct();
            return string.Join("; ", emails);
        }


        /// <summary>
        /// Moved over from old system
        /// </summary>
        /// <param name="encrypted"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public static string SGI_Decrypt(string encrypted, string password)
        {
            using (var hashmd5 = new MD5CryptoServiceProvider())
            using (var des = new TripleDESCryptoServiceProvider())
            {
                string decrypted;
                byte[] pwdhash, buff;
                pwdhash = hashmd5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(password));

                //the key is the secret password hash.
                des.Key = pwdhash;

                des.Mode = CipherMode.ECB; //CBC, CFB

                buff = Convert.FromBase64String(encrypted);

                //decrypt DES 3 encrypted byte buffer and return ASCII string
                decrypted = ASCIIEncoding.ASCII.GetString(des.CreateDecryptor().TransformFinalBlock(buff, 0, buff.Length));

                return decrypted;
            }
        }

        /// <summary>
        /// Moved over from old system
        /// </summary>
        /// <param name="original"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public static string SGI_Encrypt(string original, string password)
        {
            using (var hashmd5 = new MD5CryptoServiceProvider())
            using (var des = new TripleDESCryptoServiceProvider())
            {
                string encrypted;
                byte[] pwdhash, buff;

                pwdhash = hashmd5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(password));

                //the key is the secret password hash.
                des.Key = pwdhash;

                des.Mode = CipherMode.ECB; //CBC, CFB

                buff = ASCIIEncoding.ASCII.GetBytes(original);

                encrypted = Convert.ToBase64String(des.CreateEncryptor().TransformFinalBlock(buff, 0, buff.Length));

                return encrypted;
            }
        }

        /// <summary>
        /// moved over from old system
        /// </summary>
        public static string DecryptForLoginInfo(string value, string addedText)
        {
            var text = string.Empty;
            if (value.Length == 0)            
                return text;
            
            value = SGI_Decrypt(value, CommonConfig.PASSWORD);
            if (value.Length > addedText.Length)            
                text = value.Substring(0, value.Length - addedText.Length);

            return text;
        }

        public static string ToPhoneNoInUSFormat(this string phoneNumber)
        {
            try
            {
                var regex = new Regex(@"\d+");
                var builder = new StringBuilder();
                foreach (Match item in regex.Matches(phoneNumber))
                {
                    builder.Append(item.Value);
                }
                phoneNumber = builder.ToString();

                // 10 = Local US phone number
                if (phoneNumber.Length == 10)                
                    phoneNumber = Regex.Replace(phoneNumber, @"(\d{3})(\d{3})(\d{4})", "($1)$2-$3");                

                return phoneNumber;
            }
            catch
            {
                return string.Empty;
            }
        }

        public static T ToEnum<T>(this string value) where T : struct
        {
            T format;
            if (Enum.TryParse(value, true, out format))
                return format;

            return default(T);
        }
    }
}
